/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "timeline_manager.h"

#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <unistd.h>
#include "timeline_service.h"
#include "datetime_ex.h"
#include "timeline_rdb_manager.h"

int WORK_TIME_START = 9;
int WORK_TIME_END = 18;
int REST_TIME_START = 19;
int REST_TIME_END = 7;
int IGnore_DISTANCE = 200;
const int DISTANCE = 200;
const int TIMER_INTERVAL_CHECKRATE = 2400;
const int TIMER_INTERVAL_KMEANS = 900;
const int ERR_INVALID_FD = -1;
const double ENRTH_RADIUS = 6378.137;

namespace OHOS {
namespace Msdp {
static const int CLUSTER_NUM = 2;
void TimelineManager::TimelineCallbackDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& remote)
{
    if (remote == nullptr) {
        TIMELINE_HILOGE(TIMELINE_MODULE_SERVICE, "OnRemoteDied failed, remote is nullptr");
        return;
    }
    TIMELINE_HILOGD(TIMELINE_MODULE_SERVICE, "Recv death notice");
}

bool TimelineManager::Init()
{

    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "TimelineManager: Init start");
    if (timelineCBDeathRecipient_ == nullptr) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "timelineCBDeathRecipient_ == nullptr");
        timelineCBDeathRecipient_ = new TimelineCallbackDeathRecipient();
    }
    std::set<const sptr<ITimelineCallback>, classcomp> listeners;
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "TimelineManager: Init success");
    return true;
}

bool TimelineManager::GetData(TimelineDatabaseInfo::MovementData &data)
{
    TIMELINE_HILOGD(TIMELINE_MODULE_SERVICE, "GetData: Enter");
    TimelineRdbManager::MovementDataMap movementDataMap;
    auto tms = ms_.promote();
    tms->GetTimeRdbManager()->GetRdbMap(movementDataMap);

    TIMELINE_HILOGD(TIMELINE_MODULE_SERVICE, "LbsPositionDataCallback: size = %{public}d", movementDataMap.size());
    if (!movementDataMap.empty()) {
        int number = random(1, movementDataMap.size());
        TIMELINE_HILOGD(TIMELINE_MODULE_SERVICE, "LbsPositionDataCallback: number is : %{public}d", number);
        for (auto iter = movementDataMap.begin(); iter != movementDataMap.end(); iter++) {
            if (iter->first == number) {
                data = iter->second;
                return true;
            }
        }
    }
    return false;
}

int32_t TimelineManager::LbsPositionDataCallback(const struct SensorEvents *event, const TimelineDataUtils::TimelineArea& area)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Enter");

    struct tm time = {0};
    if (!GetSystemCurrentTime(&time)) {
        return -1;
    }
    if (getOnceMonthDataFlag_ == 0) {
        ReadRecentOneMonthData();
        getOnceMonthDataFlag_ = 1;
    } else if (time.tm_hour == 9 || kmeansUpdateFlag_ == 0) {
        ReadRecentOneMonthData();
        kmeansUpdateFlag_=1;
    }
    if (time.tm_hour == 10) {
        kmeansUpdateFlag_ = 0;
    }
    ReadRecentOneMonthData();
    TimelineDatabaseInfo::MovementData movementData;
    if (!GetData(movementData)) {
        TIMELINE_HILOGD(TIMELINE_MODULE_SERVICE, "TimelineManager::doesn't get data");
        return -1;
    }
    TIMELINE_HILOGD(TIMELINE_MODULE_SERVICE, "TimelineManager::get data");
    
    tm getTime_ = timelinedatabaseinfo_->getTime(movementData.TIME_STAMP);
    WORK_TIME_START = worktimestart_;
    WORK_TIME_END = worktimeend_;
    REST_TIME_START = resttimestart_;
    REST_TIME_END = resttimeend_;

    Position pos;
    bool positionOne_ = false;
    bool positionTwo_ = false;
    pos.xpos = movementData.LONGITUDE;
    pos.ypos = movementData.LATITUDE;
    pos.startHour = getTime_.tm_hour;
    pos.ssid = movementData.SSID;
    pos.bssid = movementData.BSSID;
   
   if ((GetDistance(centerMean_[companyvalue_], pos) <= DISTANCE) && (positionOne_ == false)) {
        positionOne_ = true;
        positionTwo_ = false;
    }

    if ((GetDistance(centerMean_[homevalue_], pos) <= DISTANCE) && (positionTwo_ == false)) {
        positionTwo_ = true;
        positionOne_ = false;
    }

    if ((positionOne_ == false) && (positionTwo_ == true) && ((pos.startHour  >= REST_TIME_START) || (pos.startHour  <= REST_TIME_END))) {
        if (homevalue_ == 0) {
            if (pos.bssid == homeBssid_) {
                TimelineDataUtils::TimelineData data = {TimelineDataUtils::TimelineArea::AREA_HOME,
                TimelineDataUtils::TimelineValue::VALUE_HOME};
                //notify timeline change
                TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "at home");
                NotifyTimelineChange(data);
            } else {
                TimelineDataUtils::TimelineData data = {TimelineDataUtils::TimelineArea::AREA_UNKNOWN,
                    TimelineDataUtils::TimelineValue::VALUE_UNKNOWN};
                //notify timeline change
                NotifyTimelineChange(data);
                TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "neither at home nor at company");
            }
        } else if (homevalue_ == 1) {
            if (pos.ssid == companySsid_) {
                TimelineDataUtils::TimelineData data = {TimelineDataUtils::TimelineArea::AREA_COMPANY,
                TimelineDataUtils::TimelineValue::VALUE_COMPANY};
                //notify timeline change
                TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "at home");
                NotifyTimelineChange(data);
            } else {
                TimelineDataUtils::TimelineData data = {TimelineDataUtils::TimelineArea::AREA_UNKNOWN,
                    TimelineDataUtils::TimelineValue::VALUE_UNKNOWN};
                //notify timeline change
                NotifyTimelineChange(data);
                TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "neither at home nor at company");
            }
        }
    } else if ((positionOne_ == true) && (positionTwo_ == false) && (pos.startHour  >= WORK_TIME_START) && (pos.startHour  <= WORK_TIME_END)) {
        if (companyvalue_ == 1) {
            if (pos.ssid == companySsid_) {
                TimelineDataUtils::TimelineData data = {TimelineDataUtils::TimelineArea::AREA_COMPANY,
                TimelineDataUtils::TimelineValue::VALUE_COMPANY};
                //notify timeline change
                TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "at company");
                NotifyTimelineChange(data);
            } else {
                TimelineDataUtils::TimelineData data = {TimelineDataUtils::TimelineArea::AREA_UNKNOWN,
                    TimelineDataUtils::TimelineValue::VALUE_UNKNOWN};
                //notify timeline change
                NotifyTimelineChange(data);
                TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "neither at home nor at company");
            }
        } else if (companyvalue_ == 0) {
            if (pos.bssid == homeBssid_) {
                TimelineDataUtils::TimelineData data = {TimelineDataUtils::TimelineArea::AREA_HOME,
                TimelineDataUtils::TimelineValue::VALUE_HOME};
                //notify timeline change
                TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "at company");
                NotifyTimelineChange(data);
            } else {
                TimelineDataUtils::TimelineData data = {TimelineDataUtils::TimelineArea::AREA_UNKNOWN,
                    TimelineDataUtils::TimelineValue::VALUE_UNKNOWN};
                //notify timeline change
                NotifyTimelineChange(data);
                TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "neither at home nor at company");
            }
        }
    } else {
        TimelineDataUtils::TimelineData data = {TimelineDataUtils::TimelineArea::AREA_UNKNOWN,
            TimelineDataUtils::TimelineValue::VALUE_UNKNOWN};
        //notify timeline change
        NotifyTimelineChange(data);
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "neither at home nor at company");
    }

    return ERR_OK;
}

int TimelineManager::GetCluster(Position means[], Position point)
{
	int temp=0;
	int label=0;
	int distance = GetDistance(means[0], point);

	for(int i = 1; i < CLUSTER_NUM; i++) {
		temp = GetDistance(means[i], point);
		if(temp < distance) {
			distance = temp;
			label = i;
		}
	}
	return label;
}

TimelineManager::Position TimelineManager::GetMeans(std::vector<Position> cluster)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Enter");
    float meansX = 0;
    float meansY = 0;
    Position newMean;
    int num = cluster.size();

    for(int i = 0; i < num; i++) {
        meansX += cluster[i].xpos;
        meansY += cluster[i].ypos;
    }

    newMean.xpos = meansX/num;
    newMean.ypos = meansY/num;

    return newMean;
}

void TimelineManager::Kmeans(const std::vector<TimelineDatabaseInfo::ListData> &listData)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Enter");
	Position means[CLUSTER_NUM];
	std::vector<Position> cluster[CLUSTER_NUM];
    std::vector<Position> centerMean(listData.size());
    centerMean_ = centerMean;
    int homeflag_ = 0;
    int companyflag_ = 0;
    int32_t homevalue_ = 0;
    int32_t companyvalue_ = 1;
    WORK_TIME_START = worktimestart_;
    WORK_TIME_END = worktimeend_;
    REST_TIME_START = resttimestart_;
    REST_TIME_END = resttimeend_;
    std::vector<int32_t> startHour(listData.size());
    std::vector<int32_t> endHour(listData.size());
    std::vector<int32_t> startMin(listData.size());
     std::vector<int32_t> endMin(listData.size());
    std::vector<int32_t> duration(listData.size());
    std::vector<TimelineDatabaseInfo::ListData> cluserTwo;
    std::vector<TimelineDatabaseInfo::ListData> cluserOne;
    std::vector<Position> meansoneTemp;
    std::vector<Position> meanstwoTemp;

    for (int i = 0; i <listData.size(); i++) {
        startHour[i] = listData[i].STARTTIMEHOUR;
        endHour[i] = listData[i].ENDTIMEHOUR;
        startMin[i] = listData[i].STARTTIMEMIN;
        endMin[i] = listData[i].ENDTIMEMIN;
        if (startHour[i] > 9 && startHour[i] <11)
        {
            cluserOne.push_back(listData[i]);
        }
        if (startHour[i] > 0 && startHour[i] <2)
        {
            cluserTwo.push_back(listData[i]);
        }
    }
    if (clearVectorFlag_ == 0) {
        CheckPosition(cluserOne, positionOneHugeDiffNumber_, positionOneHugeDiffTotalNumber_);
        CheckPosition(cluserOne, positionTwoHugeDiffNumber_, positionTwoHugeDiffTotalNumber_);
    }

    if (!(positionOneHugeDiffTotalNumber_ % 7)) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Need Manual Intervention");
    }
    if (!(positionTwoHugeDiffTotalNumber_ % 7)) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Need Manual Intervention");
    }

    homeBssid_ = GetBssidInfo(cluserTwo);
    companySsid_ = GetSsidInfo(cluserOne);
   
    for (uint32_t m = 0; m< (cluserOne.size() * cluserTwo.size()); m++)
    {
        int tempHome = random(0, cluserTwo.size());
        int tempCompany = random(0, cluserOne.size());
        means[0].xpos = cluserTwo[tempHome].LONGITUDE;
        means[0].ypos = cluserTwo[tempHome].LATITUDE;
        means[1].xpos = cluserOne[tempCompany].LONGITUDE;
        means[1].ypos = cluserOne[tempCompany].LATITUDE;

        Position pos;

        int label = 0;
        for(int i = 0; i < listData.size(); i++) {
            pos.xpos = listData[i].LONGITUDE;
            pos.ypos = listData[i].LATITUDE;
            pos.startYear = listData[i]. STARTTIMEYEAR;
            pos.startMonth = listData[i]. STARTTIMEMONTH;
            pos.startDay = listData[i]. STARTTIMEDAY;
            pos.startHour = listData[i]. STARTTIMEHOUR;
            pos.startMin = listData[i]. STARTTIMEMIN;
            pos.startSec = listData[i]. STARTTIMESEC;
            pos.endYear = listData[i]. ENDTIMEYEAR;
            pos.endMonth = listData[i]. ENDTIMEMONTH;
            pos.endDay = listData[i]. ENDTIMEDAY;
            pos.endHour = listData[i]. ENDTIMEHOUR;
            pos.endMin = listData[i]. ENDTIMEMIN;
            pos.endSec = listData[i]. ENDTIMESEC;

            label = GetCluster(means, pos);
            cluster[label].push_back(pos);
        }

        for(int i = 0; i < CLUSTER_NUM; i++) {
            means[i] = GetMeans(cluster[i]);
        }
        

        meansoneTemp.push_back(means[0]);
        meanstwoTemp.push_back(means[1]);

        for(int i = 0; i < CLUSTER_NUM; i++) {
            cluster[i].clear();
        }

        for(int i = 0; i < listData.size(); i++) {
            pos.xpos = listData[i].LONGITUDE;
            pos.ypos = listData[i].LATITUDE;
            pos.startYear = listData[i]. STARTTIMEYEAR;
            pos.startMonth = listData[i]. STARTTIMEMONTH;
            pos.startDay = listData[i]. STARTTIMEDAY;
            pos.startHour = listData[i]. STARTTIMEHOUR;
            pos.startMin = listData[i]. STARTTIMEMIN;
            pos.startSec = listData[i]. STARTTIMESEC;
            pos.endYear = listData[i]. ENDTIMEYEAR;
            pos.endMonth = listData[i]. ENDTIMEMONTH;
            pos.endDay = listData[i]. ENDTIMEDAY;
            pos.endHour = listData[i]. ENDTIMEHOUR;
            pos.endMin = listData[i]. ENDTIMEMIN;
            pos.endSec = listData[i]. ENDTIMESEC;

            label = GetCluster(means, pos);
            cluster[label].push_back(pos);
        }
        if (m>2 && ((GetDistance(meansoneTemp[m], meansoneTemp[m - 1])) < IGnore_DISTANCE)
            && ((GetDistance(meanstwoTemp[m], meanstwoTemp[m - 1])) < IGnore_DISTANCE)
            && ((GetDistance(meansoneTemp[m - 1], meansoneTemp[m - 2]))<IGnore_DISTANCE)
            && ((GetDistance(meanstwoTemp[m - 1], meanstwoTemp[m - 2])) < IGnore_DISTANCE)
            && ((GetDistance(meansoneTemp[m], meansoneTemp[m - 2])) < IGnore_DISTANCE)
            && ((GetDistance(meanstwoTemp[m], meanstwoTemp[m - 2])) < IGnore_DISTANCE))
        {
            continue;
        }
    }


	for(int label = 0; label < CLUSTER_NUM; label++) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "The cluster group is: %{public}d", label + 1);
		std::vector<Position> pos;
        pos = cluster[label];
        
		for(unsigned int i = 0; i < pos.size(); i++) {
            if (pos[i].startHour < WORK_TIME_END && pos[i].startHour> WORK_TIME_START) {
                companyflag_++;
            } else if (pos[i].startHour > REST_TIME_START || pos[i].startHour< REST_TIME_END) {
                homeflag_++;
             }
		 }
         if (companyflag_ > homeflag_){
           centerMean_[companyvalue_] = means[label];
           if (companyHumanSetFlag_ == 1) {
               centerMean_[companyvalue_].xpos = companylongitude_;
               centerMean_[companyvalue_].ypos = companylatitude_;
               if (GetDistance(centerMean_[companyvalue_], means[label]) > IGnore_DISTANCE) {
                   companyMeansHugDiffNumber_++;
                   if (!(companyMeansHugDiffNumber_ % 7)) {
                        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Need Manual Intervention ");
                        centerMean_[companyvalue_] = means[label];
                   }
               }
           }
       }else {
           centerMean_[homevalue_] = means[label];
            if (homeHumanSetFlag_ == 1) {
               centerMean_[homevalue_].xpos = homelongitude_;
               centerMean_[homevalue_].ypos = homelatitude_;
               if (GetDistance(centerMean_[homevalue_], means[label]) > IGnore_DISTANCE) {
                   homeMeansHugDiffNumber_++;
                   if (!(homeMeansHugDiffNumber_ % 7)) {
                        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Need Manual Intervention ");
                        centerMean_[homevalue_] = means[label];
                   }
               }
           }
        }
	}
}


void TimelineManager::ReadRecentOneMonthData()
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Enter");
    Position pos;
    TimelineRdbManager::TimelineDatabaseMap timelineDatabaseMap;
    auto tms = ms_.promote();
    tms->GetTimeRdbManager()->GetListMap(timelineDatabaseMap);
    if (!timelineDatabaseMap.empty()) {
        for (auto iter = timelineDatabaseMap.begin(); iter != timelineDatabaseMap.end(); iter++) {
            listData.push_back(iter->second);
        }

        Kmeans(listData);

        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Naive Bayes Enter");

        for (auto iter = timelineDatabaseMap.begin(); iter != timelineDatabaseMap.end(); iter++) {
            pos.xpos = iter->second.LONGITUDE;
            pos.ypos = iter->second.LATITUDE;
            pos.startHour =  iter->second.STARTTIMEHOUR;
            pos.endHour = iter->second.ENDTIMEHOUR;

            for (int k = pos.startHour; k< pos.endHour - pos.startHour; k++) {
                if (k > 23) {
                    k = 0;
                }
                oclock[k].totalnumber++;

                if (GetDistance(centerMean_[homevalue_], pos) > IGnore_DISTANCE) {
                    oclock[k].homenumber++;
                } else if (GetDistance(centerMean_[companyvalue_], pos) > IGnore_DISTANCE) {
                    oclock[k].companynumber++;
                } else {
                    oclock[k].unknownnumber++;
                }
            }
        }
    }
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Exit");
    // Kmeans(timelineInfo);
}

void TimelineManager::GetTraceRate()
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Enter");
    const int HOURSINONEDAY = 24;
    const int LAPLACE = 1;
    const int LAPLACE_NI = 3;
    for (int k = 0; k < HOURSINONEDAY; k++) {
        rate[k].companyrate = (oclock[k].companynumber + LAPLACE) / (oclock[k].totalnumber + LAPLACE_NI);
        rate[k].homerate = (oclock[k].homenumber + LAPLACE) / (oclock[k].totalnumber + LAPLACE_NI);
        rate[k].unknownrate = (oclock[k].unknownnumber + LAPLACE) / (oclock[k].totalnumber + LAPLACE_NI);
    }
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Exit");
}

void TimelineManager::CheckRate(uint32_t time)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Enter");
    if (rate[time].companyrate > rate[time].homerate) {
        if (rate[time].companyrate > rate[time].unknownrate) {
            forcecastPosition_ = TimelineDatabaseInfo::ForcecastPosition::COMPANY;
        } else {
            forcecastPosition_ = TimelineDatabaseInfo::ForcecastPosition::UNKNOWN;
        } 
    } else if (rate[time].homerate > rate[time].unknownrate) {
            forcecastPosition_ = TimelineDatabaseInfo::ForcecastPosition::HOME;
        } else {
            forcecastPosition_ = TimelineDatabaseInfo::ForcecastPosition::UNKNOWN;
        }
        forcecastPosition = forcecastPosition_;
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "CheckRate: forcecastPosition is : %{public}d", forcecastPosition);
        // return forcecastPosition;
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Exit");
}

TimelineDatabaseInfo::ForcecastPosition TimelineManager::GetForcecastPosition()
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Enter");
    return forcecastPosition;
}

void TimelineManager::NotifyTimelineChange(const TimelineDataUtils::TimelineData& timelineData)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Enter");

    // Call back for all listeners
    std::set<const sptr<ITimelineCallback>, classcomp> listeners;
    bool isExists = false;
    TimelineDataUtils::TimelineData ErrData;
    for (auto it = listenerMap_.begin(); it != listenerMap_.end(); ++it) {
        if (it->first == timelineData.area) {
            TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "NotifyTimelineChange : first == timelineData.area");
            isExists = true;
            listeners = (std::set<const sptr<ITimelineCallback>, classcomp>)(it->second);
            break;
        }
    }
    if (!isExists) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "No listener found for area: %{public}d", timelineData.area);
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Exit");
        return;
    }
    for (auto& listener : listeners) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "OnTimerlineChanged");
        if (timelineData.area !=  TimelineDataUtils::TimelineArea::AREA_HOME &&
            timelineData.area !=  TimelineDataUtils::TimelineArea::AREA_COMPANY &&
            timelineData.area !=  TimelineDataUtils::TimelineArea::AREA_UNKNOWN) {
                ErrData.area = TimelineDataUtils::TimelineArea::AREA_WRONGPOSITIONINFO;
                ErrData.value = TimelineDataUtils::TimelineValue::VALUE_WRONGPOSITIONINFO;
                listener->OnTimelineChanged(ErrData);
                return;
            }
        listener->OnTimelineChanged(timelineData);
    }
}

void TimelineManager::Subscribe(const TimelineDataUtils::TimelineArea& area,
    const sptr<ITimelineCallback>& callback)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Enter");
    std::lock_guard lock(mutex_);
    TIMELINE_RETURN_IF(callback == nullptr);
    auto object = callback->AsObject();
    TIMELINE_RETURN_IF(object == nullptr);
    std::set<const sptr<ITimelineCallback>, classcomp> listeners;
    bool isExists = false;
    for (auto it = listenerMap_.begin(); it != listenerMap_.end(); ++it) {
        if (it->first == area) {
            isExists = true;
            listeners = (std::set<const sptr<ITimelineCallback>, classcomp>)(it->second);
            break;
        }
    }
    auto retIt = listeners.insert(callback);
    if (retIt.second) {
        object->AddDeathRecipient(timelineCBDeathRecipient_);
    }

    if (!isExists) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "!isExists");
        std::pair<TimelineDataUtils::TimelineArea, std::set<const sptr<ITimelineCallback>, classcomp>> pair =
            std::make_pair(area, listeners);
        listenerMap_.insert(pair);
    }
    LbsPositionDataCallback(nullptr, area);
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Exit");
}

void TimelineManager::UnSubscribe(const TimelineDataUtils::TimelineArea& area, const sptr<ITimelineCallback>& callback)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Enter");
    std::lock_guard lock(mutex_);
    TIMELINE_RETURN_IF(callback == nullptr);
    auto object = callback->AsObject();
    TIMELINE_RETURN_IF(object == nullptr);
    std::set<const sptr<ITimelineCallback>, classcomp> listeners;
    bool isExists = false;
    for (auto it = listenerMap_.begin(); it != listenerMap_.end(); ++it) {
        if (it->first == area) {
            isExists = true;
            listeners = (std::set<const sptr<ITimelineCallback>, classcomp>)(it->second);
            break;
        }
    }
    if (!isExists) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "No listener found for area: %{public}d", area);
        return;
    }

    size_t eraseNum = listeners.erase(callback);
    if (eraseNum != 0) {
        object->RemoveDeathRecipient(timelineCBDeathRecipient_);
    }
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Exit");
}

bool TimelineManager::UpdatePositionState(int32_t homevalue, int32_t companyvalue)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "UpdatePositionState: fun is start");
    if (homevalue > CLUSTER_NUM || companyvalue > CLUSTER_NUM) {
        return false;
    }
    homevalue_ = homevalue;
    companyvalue_ = companyvalue;
    return true;
}

bool TimelineManager::UpdateHomePosition(double longitude, double latitude)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "UpdatePositionState: fun is start");
    homelongitude_ = longitude;
    homelatitude_ = latitude;
    homeHumanSetFlag_ = 1;
    return true;
}

bool TimelineManager::UpdateCompanyPosition(double longitude, double latitude)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "UpdatePositionState: fun is start");
    companylongitude_ = longitude;
    companylatitude_ = latitude;
    companyHumanSetFlag_ = 1;
    return true;
}

bool TimelineManager::UpdateRestTime(int32_t resttimestart, int32_t resttimeend)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "UpdatePositionState: fun is start");
    resttimestart_ = resttimestart;
    resttimeend_ = resttimeend;
    return true;
}

bool TimelineManager::UpdateWorkTime(int32_t worktimestart, int32_t worktimeend)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "UpdatePositionState: fun is start");
    worktimestart_ = worktimestart;
    worktimeend_ = worktimeend;
    return true;
}

uint32_t TimelineManager::GetRestTimeStart() 
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "resttimestart is : %{public}d", resttimestart_);
    return resttimestart_;
}

uint32_t TimelineManager::GetRestTimeEnd() 
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "resttimeend is : %{public}d", resttimeend_);
    return resttimeend_;
}

uint32_t TimelineManager::GetWorkTimeStart() 
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "worktimestart is : %{public}d", worktimestart_);
    return worktimestart_;
}

uint32_t TimelineManager::GetWorkTimeEnd() 
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "worktimeend is : %{public}d", worktimeend_);
    return worktimeend_;
}

void TimelineManager::InitKmeansTimer()
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "enter");
    managerEpFd_ = epoll_create1(EPOLL_CLOEXEC);
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "managerEpFd_: %{public}d", managerEpFd_);
    if (managerEpFd_ == -1) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "create epoll fd fail.");
    }
    kmeansTimerFd_ = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "kmeansTimerFd_: %{public}d", kmeansTimerFd_);
    if (kmeansTimerFd_ == ERR_INVALID_FD) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "create timer fd fail.");
    }
    SetTimerInterval(TIMER_INTERVAL_KMEANS);
    fcntl(kmeansTimerFd_, F_SETFL, O_NONBLOCK);
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "start callback");
    callbacks_.insert(std::make_pair(kmeansTimerFd_, &TimelineManager::KmeansTimerCallback));
    if (RegisterTimerCallback(kmeansTimerFd_, EVENT_TIMER_FD)) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "register timer fd fail.");
    }
}

void TimelineManager::KmeansTimerCallback()
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "enter");
    unsigned long long timers;
    if (read(kmeansTimerFd_, &timers, sizeof(timers)) == -1) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "read timer fd fail.");
        return;
    }
    Kmeans(listData);
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "exit");
}

void TimelineManager::InitCheckRateTimer()
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "enter");
    managerEpFd_ = epoll_create1(EPOLL_CLOEXEC);
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "managerEpFd_: %{public}d", managerEpFd_);
    if (managerEpFd_ == -1) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "create epoll fd fail.");
    }
    rateTimerFd_ = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "rateTimerFd_: %{public}d", rateTimerFd_);
    if (rateTimerFd_ == ERR_INVALID_FD) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "create timer fd fail.");
    }
    SetTimerInterval(TIMER_INTERVAL_CHECKRATE);
    fcntl(rateTimerFd_, F_SETFL, O_NONBLOCK);
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "start callback");
    callbacks_.insert(std::make_pair(rateTimerFd_, &TimelineManager::CheckRateTimerCallback));
    if (RegisterTimerCallback(rateTimerFd_, EVENT_TIMER_FD)) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "register timer fd fail.");
    }
}

void TimelineManager::CheckRateTimerCallback()
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "enter");
    unsigned long long timers;
    if (read(rateTimerFd_, &timers, sizeof(timers)) == -1) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "read timer fd fail.");
        return;
    }
    struct tm time = {0};
    if (!GetSystemCurrentTime(&time)) {
        return;
    }
    CheckRate((time.tm_hour + 1));
    if (ForcecastNextPosition()) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Nest Position will Change!");
    }
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "exit");
}

int TimelineManager::RegisterTimerCallback(const int fd, const EventType et)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "enter");
    struct epoll_event ev;

    ev.events = EPOLLIN;
    if (et == EVENT_TIMER_FD) {
        ev.events |= EPOLLWAKEUP;
    }

    ev.data.ptr = reinterpret_cast<void*>(this);
    ev.data.fd = fd;
    if (epoll_ctl(managerEpFd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "epoll_ctl failed, error num =%{public}d", errno);
        return -1;
    }

    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "exit");
    return 0;
}

void TimelineManager::SetTimerInterval(int interval)
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "enter");
    struct itimerspec itval;

   if (kmeansTimerFd_ == ERR_INVALID_FD) {
        return;
    }
   if (rateTimerFd_ == ERR_INVALID_FD) {
        return;
    }

    timerInterval_ = interval;

    if (interval < 0) {
        interval = 0;
    }

    itval.it_interval.tv_sec = interval;
    itval.it_interval.tv_nsec = 0;
    itval.it_value.tv_sec = interval;
    itval.it_value.tv_nsec = 0;

    if (timerfd_settime(kmeansTimerFd_, 0, &itval, nullptr) == -1) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "set timer failed");
    }
    if (timerfd_settime(rateTimerFd_, 0, &itval, nullptr) == -1) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "set timer failed");
    }

    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "exit");
    return;
}

void TimelineManager::StartThread()
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "enter");
    std::make_unique<std::thread>(&TimelineManager::LoopingThreadEntry, this)->detach();
}

void TimelineManager::LoopingThreadEntry()
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "enter");
    int nevents = 0;
    size_t cbct = callbacks_.size();
    struct epoll_event events[cbct];

    while (true) {
        int timeout = 0;

        nevents = epoll_wait(managerEpFd_, events, cbct, timeout);
        if (nevents == -1) {
            continue;
        }
        for (int n = 0; n < nevents; ++n) {
            TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "start event");
            if (events[n].data.ptr) {
                TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "get data");
                TimelineManager *func = const_cast<TimelineManager *>(this);
                TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "events[n].data.ptr: %{public}d", events[n].data.u32);
                (callbacks_.find(events[n].data.fd)->second)(func);
            }
        }
    }
}

bool TimelineManager::ForcecastNextPosition()
{
    TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Enter");
    if (forcecastPositionTemp_ != GetForcecastPosition()) {
        forcecastPositionTemp_ = GetForcecastPosition();
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Will Change Position in Next Hour which is : %{public}d", forcecastPositionTemp_);
        return 1;
    }
    return 0;
}

std::string TimelineManager::GetSsidInfo(const std::vector<TimelineDatabaseInfo::ListData> &Temp)
    // const std::vector<TimelineDatabaseInfo::ListData> &cluserOne)
{
    for (int i = 0; i < Temp.size(); i++)
    {
        TIMELINE_HILOGD(TIMELINE_MODULE_SERVICE, "GetBssidInfo::SSID_ :%{public}s", Temp[i].SSID.c_str());
        ssidInfo.SSID = Temp[i].SSID;
        if (SsidInfoTemp.size() == 0) {
            SsidInfoTemp.push_back(ssidInfo);
        }
        for (int j = 0;j < SsidInfoTemp.size(); j++) {
            if (SsidInfoTemp[j].SSID == ssidInfo.SSID) {
                SsidInfoTemp[j].number++;
                break;
            }
            SsidInfoTemp.push_back(ssidInfo);
        }
    }
    return GetPositionSsidInfo(SsidInfoTemp);
}

std::string TimelineManager::GetPositionSsidInfo(const std::vector<SsidInfo> &ssidInfo)
{
    if (ssidInfo.size() == 1) {
        SSID_ = ssidInfo[0].SSID;
    }
    for (int i = 1; i< ssidInfo.size(); i++) {
        if (ssidInfo[i].number > ssidInfo[i-1].number) {
            SSID_ = ssidInfo[i].SSID;
        } else {
            SSID_ = ssidInfo[i-1].SSID;
        }
    }
    TIMELINE_HILOGD(TIMELINE_MODULE_SERVICE, "LbsPositionDataCallback::SSID_ :%{public}s", SSID_.c_str());
    return SSID_;
}

std::string TimelineManager::GetBssidInfo(const std::vector<TimelineDatabaseInfo::ListData> &Temp)
    // const std::vector<TimelineDatabaseInfo::ListData> &cluserOne)
{
    for (int i = 0; i < Temp.size(); i++)
    {
        TIMELINE_HILOGD(TIMELINE_MODULE_SERVICE, "GetBssidInfo::BSSID_ :%{public}s", Temp[i].BSSID.c_str());
        bssidInfo.BSSID = Temp[i].BSSID;
        if (BssidInfoTemp.size() == 0) {
            BssidInfoTemp.push_back(bssidInfo);
        }
        for (int j = 0;j < BssidInfoTemp.size(); j++) {
            if (BssidInfoTemp[j].BSSID == bssidInfo.BSSID) {
                BssidInfoTemp[j].number++;
                break;
            }
            BssidInfoTemp.push_back(bssidInfo);
            
        }
    }
    return GetPositionBssidInfo(BssidInfoTemp);
}

std::string TimelineManager::GetPositionBssidInfo(const std::vector<BssidInfo> &bssidInfo)
{
    if (bssidInfo.size() == 1) {
        BSSID_ = bssidInfo[0].BSSID;
    }
    for (int i = 1; i< bssidInfo.size(); i++) {
        if (bssidInfo[i].number > bssidInfo[i-1].number) {
            BSSID_ = bssidInfo[i].BSSID;
        } else {
            BSSID_ = bssidInfo[i-1].BSSID;
        }
    }
    TIMELINE_HILOGD(TIMELINE_MODULE_SERVICE, "GetPositionBssidInfo::BSSID_ :%{public}s", BSSID_.c_str());
    return BSSID_;
}

double TimelineManager::Rad(double positionInfo)
{
    return positionInfo * M_PI / 180.0;
}

double TimelineManager::GetDistance(Position pos1, Position pos2)
{
    double radLat1 = Rad(pos1.ypos);
    double radLat2 = Rad(pos1.ypos);
    double a = radLat1 - radLat2;
    double b = Rad(pos1.xpos) - Rad(pos2.xpos);
    double s = 2 * asin(sqrt(pow(sin(a / 2), 2)
		+ cos(radLat1) * cos(radLat2)
        * pow(sin(b / 2), 2)));
    s = s * ENRTH_RADIUS;
    s = round(s * 10000);
    s = s / 10;
    return s ;
}

void TimelineManager::CheckPosition(std::vector<TimelineDatabaseInfo::ListData>  &cluser, int positionHugeDiffNumber_, int positionHugeDiffTotalNumber_)
{
    Position posi;
    Position posj;
    int size = cluser.size();
    for (auto itor = cluser.begin(); itor != cluser.end(); itor++) {
        posi.xpos = itor->LONGITUDE;
        posi.ypos = itor->LATITUDE;
        for (int j = 0; j < cluser.size(); j++) {
            posj.xpos = cluser[j].LONGITUDE;
            posj.ypos = cluser[j].LATITUDE;
            if (GetDistance(posi, posj) > IGnore_DISTANCE) {
                positionHugeDiffNumber_ ++;
            }
        }
        if (positionHugeDiffNumber_ > cluser.size() * 2/3) {
            cluser.erase(itor);
            positionHugeDiffTotalNumber_++;
            TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Need Manual Intervention");
        }
    }
    if (cluser.size() < size*(1/5)) {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "Need Manual Intervention");
        clearVectorFlag_ = 1;
    } else {
        clearVectorFlag_ = 0;
    }
}
} // namespace Msdp
} // namespace OHOS
